home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / tool chest / development kits / hypercard related / xcmds & xfcns / alias xfcn 1.3 / source / alias.c next >
Encoding:
C/C++ Source or Header  |  1993-06-13  |  22.0 KB  |  901 lines

  1. /* -----------------------------------------------------------------
  2.     File:            alias.c
  3.                     XFCN to do 7.0 Alias stuff
  4.     
  5.     Version:        see kVersionStr below
  6.     
  7.     History:        11-06-90 1.0d1 JRP    from volCheck.c
  8.                     11-12-90 1.0d2 JRP    put version stuff in vers.h
  9.                     11-13-90 1.0d3 JRP    add trap and gestalt checking
  10.                     11-16-90 1.0d4 JRP    add findStrResId
  11.                                         revise cmpStrtoResNum params
  12.                                         revise returnMsgNum params
  13.                     03-21-91 1.1d1 JRP    add complete return for GetAliasInfo
  14.                     03-22-91 1.1d2 JRP    return GetAliasInfo as return-delimited
  15.                     04-09-93 1.2   JRP    fix bogus Gestalt call in Trap.c.
  16.                     04-14-93 1.3   JRP    add ResolveAliasToPath
  17.     
  18.     Author:            John R. Powers, III
  19.                     Instructional Products Department
  20.                     Apple Computer, Inc.
  21.                     AppleLink: JohnPowers
  22.     
  23.     Copyright:        see vers.h and "copyright" below.
  24.  
  25.     Computer:        Mac Quadra 950 with System 7.1
  26.     
  27.     Compiler:        MPW v3.2
  28.  
  29.     Usage:
  30.     
  31.         
  32.         Requires HyperCard version 1.2 or better.
  33.         
  34.     Files:
  35.     
  36.         alias.c            This source file
  37.         alias.r            Rez source
  38.         vers.h            header with version information
  39.         trap.c            source with trap functions
  40.         trap.pro        prototypes for trap.c
  41.         makefileAlias    make file
  42.         aliasLab        HyperCard stack for testing
  43.         
  44.     Full Build:
  45.     
  46.         see makefileAlias
  47.  
  48.         
  49. ----------------------------------------------------------------- */
  50.  
  51. #include    <HyperXCmd.h>
  52. #include    <Types.h>
  53. #include    <CType.h>
  54. #include    <String.h>            // strcpy…
  55. #include    <Strings.h>            // c2pstr…
  56. #include    <PLStringFuncs.h>    // PLstrcpy…
  57. #include    <Memory.h>
  58. #include    <ToolUtils.h>
  59. #include    <Resources.h>
  60. #include    <Packages.h>
  61. #include    <Files.h>
  62. #include    <Errors.h>
  63.  
  64. #include    <Aliases.h>
  65.  
  66. /*
  67.         Constants
  68. */
  69.  
  70. #define        kCterm            '\0'
  71. #define        kColon            ':'
  72. #define        kReturn            '\n'
  73. #define        kComma            ','
  74. #define        kSpace            ','
  75. #define        kCommaStr        ","
  76. #define        kReturnStr        "\n"
  77. #define        kColonStr        ":"
  78. #define        kSpaceStr        " "
  79. #define        kNoStringResource    "Err 00 Missing STR# for "
  80. #define        kNoErrNum        0    /*    don't want to return an error code    */
  81.  
  82. #include "vers.h"                /*     version and copyright info            */
  83.  
  84. enum                            /*    STR# indices                        */
  85.     {
  86.         ksCmdVersion=1,            /*    first of commands                    */
  87.         ksCmdHelp,
  88.         ksCmdMakeAlias,
  89.         ksCmdResolveAlias,
  90.         ksCmdVerifyAlias,        /*    phantom command for debugging only    */
  91.         ksCmdGetAliasInfo,
  92.         ksCmdResolveAliasToPath,
  93.         ksHelpDesc,                /*    help description                    */
  94.         ksCallback,                /*    callback string for HyperCard        */
  95.         ksErrCommandWhere,        /*    first of error messages                */
  96.         ksErrCommandHuh,        /*    Err 02    */
  97.         ksErrMissingParam,        /*    Err 03    */
  98.         ksErrNoAliasMgr,        /*    Err 04    */
  99.         ksErrEvalExpr,            /*    Err 05    */
  100.         ksErrFSMakeFSSpec,        /*    Err 06    */
  101.         ksErrNewAlias,            /*    Err 07    */
  102.         ksErrResolveAlias,        /*    Err 08    */
  103.         ksErrResolveAliasFile,    /*    Err 09    */
  104.         ksErrGetAliasInfoZone,    /*    Err 10    */
  105.         ksErrGetAliasInfoServer,/*    Err 11    */
  106.         ksErrGetAliasInfoVolume,/*    Err 12    */
  107.         ksErrGetAliasInfoParent    /*    Err 13    */
  108.     };
  109.  
  110. /*
  111.         Prototypes
  112. */
  113.  
  114. void addColon(Str255);
  115. void addStrItemToList(char *, char *);
  116. void addNumItemToList(char *, long);
  117. short cmpStrtoResNum(Str255, short, short);
  118. void convertDataToHexStr(char *, Handle);
  119. void convertFSSpecToStr(char *, FSSpecPtr);
  120. void convertHexStrToData(char *, Handle *);
  121. void convertStrToFSSpec(char *, FSSpecPtr);
  122. void copyPtoCstr(char *, Str255);
  123. Handle copyStrToHand(char *);
  124. void deleteColon(Str255);
  125. short equalPstr(Str255, Str255);
  126. short findStrResId(Str255);
  127. void getItemFromCList(char *, short, char *);
  128. void getItemFromPList(Str255, short, Str255);
  129. void handleToCstr(char *, Handle);
  130. void handleToPstr(Str255, Handle);
  131. void insertParent(char *, char *, char *);
  132. void pathNameFromFSSpec(Str255 pathName, FSSpec* fileSpec);
  133. void returnMsgNum(XCmdPtr, short, short, long);
  134.  
  135. #include    "trap.pro"
  136.  
  137. /*
  138.         Main program and entry point for XFCN.
  139. */
  140.  
  141. pascal void    entryPoint(paramPtr)
  142. /*
  143. */
  144.  
  145.     XCmdPtr     paramPtr;        /*    the HyperCard connection        */
  146. {
  147.     char        resultStr[1024],
  148.                 aliasStr[256],
  149.                 copyright[]=kCopyrightStr;
  150.     Str255        command,
  151.                 resPstr,
  152.                 stackPathPstr;
  153.     OSErr        err;
  154.     Handle        hLongStackName;
  155.     Ptr            pLongStackName;
  156.     FSSpec        fileSpec;
  157.     AliasHandle    hAlias;
  158.     Boolean        bWasChanged,
  159.                 bResolveAliasChains,
  160.                 bTargetIsFolder,
  161.                 bWasAliased;
  162.     short        strResId;
  163.     
  164.     *resultStr = kCterm;
  165.     if(paramPtr->paramCount<0)
  166.         return;                    /*    an event, ignore            */
  167.                                 /*    find resource ID to use        */
  168.                                 /*    for our string resource        */
  169.     strResId = findStrResId(kProgNameStr);
  170.     if(!strResId)
  171.     {
  172.         strcpy(resultStr, kNoStringResource);
  173.         strcat(resultStr, kProgNameStr);
  174.         paramPtr->returnValue = copyStrToHand(resultStr);
  175.         return;
  176.     }
  177.                                 /*    check for command            */
  178.     if(paramPtr->paramCount==0)
  179.     {
  180.         returnMsgNum(paramPtr, ksErrCommandWhere, strResId, kNoErrNum);
  181.         return;
  182.     }
  183.     handleToPstr(command, paramPtr->params[0]);
  184.                                 /*     version command?            */
  185.     if(cmpStrtoResNum(command, ksCmdVersion, strResId))
  186.     {
  187.                 // Version
  188.  
  189.         strcpy(resultStr, kProgNameStr);
  190.         strcat(resultStr, kSpaceStr);
  191.         strcat(resultStr, kVersionStr);
  192.         strcat(resultStr, kSpaceStr);
  193.         strcat(resultStr, kAuthorStr);
  194.         paramPtr->returnValue = copyStrToHand(resultStr);
  195.         return;
  196.     }
  197.                                 /*     help command?                */
  198.     else if(cmpStrtoResNum(command, ksCmdHelp, strResId))
  199.     {
  200.             // Help
  201.  
  202.         returnMsgNum(paramPtr, ksHelpDesc, strResId, kNoErrNum);
  203.         return;
  204.     }
  205.                                 /*    is there an alias manager?    */
  206.     else if(!aliasAvailable())
  207.     {
  208.         returnMsgNum(paramPtr, ksErrNoAliasMgr, strResId, kNoErrNum);
  209.         return;
  210.     }
  211.         /*    The following commands require the Alias Manager    */
  212.     if(cmpStrtoResNum(command, ksCmdMakeAlias, strResId))
  213.     {
  214.                 // MakeAlias
  215.                 // Make an alias record.
  216.  
  217.         if(paramPtr->paramCount==2)
  218.             handleToPstr(stackPathPstr, paramPtr->params[1]);
  219.         else
  220.         {        /*    path not given, use current stack            */
  221.             GetIndString(resPstr, strResId, ksCallback);
  222.             hLongStackName = EvalExpr(paramPtr, resPstr);
  223.             if(hLongStackName==nil || paramPtr->result==xresFail)
  224.             {
  225.                 returnMsgNum(paramPtr, ksErrEvalExpr, strResId, kNoErrNum);
  226.                 return;
  227.             }
  228.                     /*    extract path name from long stack name    */
  229.                     /*    stack "<path to stack>"                    */
  230.             HLock(hLongStackName);
  231.             pLongStackName = *hLongStackName;
  232.             while(*pLongStackName!='"' && *pLongStackName!=0)
  233.                 pLongStackName++;
  234.             pLongStackName++;
  235.             stackPathPstr[0] = 0;
  236.             while(*pLongStackName!='"' && *pLongStackName!=0)
  237.                 stackPathPstr[++stackPathPstr[0]] = *pLongStackName++;
  238.             DisposHandle(hLongStackName);
  239.         }
  240.         if(err = FSMakeFSSpec(0, 0L, stackPathPstr, &fileSpec))
  241.         {
  242.             addStrItemToList(resultStr, p2cstr(stackPathPstr));
  243.             GetIndString(resPstr, strResId, ksErrFSMakeFSSpec);
  244.             addStrItemToList(resultStr, p2cstr(resPstr));
  245.             addNumItemToList(resultStr, err);
  246.             paramPtr->returnValue = copyStrToHand(resultStr);
  247.             return;
  248.         }
  249.         if(err = NewAlias(nil, &fileSpec, &hAlias))
  250.         {
  251.             returnMsgNum(paramPtr, ksErrNewAlias, strResId, err);
  252.             return;
  253.         }
  254.         convertDataToHexStr(aliasStr, (Handle) hAlias);
  255.         paramPtr->returnValue = copyStrToHand(aliasStr);
  256.         DisposHandle((Handle) hAlias);
  257.         return;
  258.     }
  259.     else if(cmpStrtoResNum(command, ksCmdResolveAlias, strResId))
  260.     {
  261.                 // ResolveAlias
  262.                 // Resolve the alias and return the FSSpec for the file.
  263.  
  264.         if(paramPtr->paramCount<2)
  265.         {
  266.             returnMsgNum(paramPtr, ksErrMissingParam, strResId, err);
  267.             return;
  268.         }
  269.         else
  270.         {
  271.             handleToCstr(aliasStr, paramPtr->params[1]);
  272.             convertHexStrToData(aliasStr, &((Handle) hAlias));
  273.             if(err = ResolveAlias(nil, hAlias, &fileSpec, &bWasChanged))
  274.             {
  275.                 returnMsgNum(paramPtr, ksErrResolveAlias, strResId, err);
  276.                 DisposHandle((Handle) hAlias);
  277.                 return;
  278.             }
  279.             bResolveAliasChains = true;
  280.             if(err = ResolveAliasFile(&fileSpec, bResolveAliasChains,
  281.                                         &bTargetIsFolder, &bWasAliased))
  282.             {
  283.                 returnMsgNum(paramPtr, ksErrResolveAliasFile, strResId, err);
  284.                 DisposHandle((Handle) hAlias);
  285.                 return;
  286.             }
  287.             convertFSSpecToStr(resultStr, &fileSpec);
  288.             paramPtr->returnValue = copyStrToHand(resultStr);
  289.             DisposHandle((Handle) hAlias);
  290.             return;
  291.         }
  292.     }
  293.     else if(cmpStrtoResNum(command, ksCmdVerifyAlias, strResId))
  294.     {
  295.                 // VerifyAlias
  296.                 // This command is only used for debugging.
  297.  
  298.         if(paramPtr->paramCount<2)
  299.         {
  300.             returnMsgNum(paramPtr, ksErrMissingParam, strResId, err);
  301.             return;
  302.         }
  303.         else
  304.         {
  305.             handleToCstr(aliasStr, paramPtr->params[1]);
  306.             convertHexStrToData(aliasStr, &((Handle) hAlias));
  307.             convertDataToHexStr(resultStr, (Handle) hAlias);
  308.             paramPtr->returnValue = copyStrToHand(resultStr);
  309.             DisposHandle((Handle) hAlias);
  310.             return;
  311.         }
  312.     }
  313.     else if(cmpStrtoResNum(command, ksCmdGetAliasInfo, strResId))
  314.     {
  315.                 // GetAliasInfo
  316.                 // Return the information in the alias record
  317.                 // as a FSSpec string.
  318.  
  319.         if(paramPtr->paramCount<2)
  320.         {
  321.             returnMsgNum(paramPtr, ksErrMissingParam, strResId, err);
  322.             return;
  323.         }
  324.         else
  325.         {
  326.             Str63    zonePstr,
  327.                     serverPstr,
  328.                     volumePstr,
  329.                     parentPstr;
  330.             short    index=0,
  331.                     notAtRoot=true;
  332.             /*    
  333.                 We return the alias information from left-to-right,
  334.                 zone-to-target, but build it from right to left.
  335.             */
  336.             handleToCstr(aliasStr, paramPtr->params[1]);
  337.             convertHexStrToData(aliasStr, &((Handle) hAlias));
  338.             *resultStr = 0;
  339.             /*
  340.                 Build path from target up to root.  Separate with colons.
  341.             */
  342.             while(notAtRoot)
  343.             {
  344.                 if(err = GetAliasInfo(hAlias, index++, parentPstr))
  345.                 {
  346.                     returnMsgNum(paramPtr, ksErrGetAliasInfoParent, strResId, index-1);
  347.                     DisposHandle((Handle) hAlias);
  348.                     return;
  349.                 }
  350.                 else if(notAtRoot=(parentPstr[0]!=0))
  351.                 {
  352.                     if(index)
  353.                         insertParent(resultStr, p2cstr(parentPstr), kColonStr);
  354.                     else    /*    first (target) entry in path, no separator    */
  355.                         strcpy(resultStr, p2cstr(parentPstr));
  356.                 }
  357.             }
  358.             /*
  359.                 Continue with volume and colon to complete path
  360.             */
  361.             if(err = GetAliasInfo(hAlias, asiVolumeName, volumePstr))
  362.             {
  363.                 returnMsgNum(paramPtr, ksErrGetAliasInfoVolume, strResId, kNoErrNum);
  364.                 DisposHandle((Handle) hAlias);
  365.                 return;
  366.             }
  367.             insertParent(resultStr, p2cstr(volumePstr), kColonStr);
  368.             /*
  369.                 Continue with server and comma
  370.             */
  371.             if(err = GetAliasInfo(hAlias, asiServerName, serverPstr))
  372.             {
  373.                 returnMsgNum(paramPtr, ksErrGetAliasInfoServer, strResId, kNoErrNum);
  374.                 DisposHandle((Handle) hAlias);
  375.                 return;
  376.             }
  377.             insertParent(resultStr, p2cstr(serverPstr), kReturnStr);
  378.             /*
  379.                 Finally zone and comma
  380.             */
  381.             if(err = GetAliasInfo(hAlias, asiZoneName, zonePstr))
  382.             {
  383.                 returnMsgNum(paramPtr, ksErrGetAliasInfoZone, strResId, kNoErrNum);
  384.                 DisposHandle((Handle) hAlias);
  385.                 return;
  386.             }
  387.             insertParent(resultStr, p2cstr(zonePstr), kReturnStr);
  388.             /*
  389.                 All done, return to caller
  390.             */
  391.             paramPtr->returnValue = copyStrToHand(resultStr);
  392.             DisposHandle((Handle) hAlias);
  393.             return;
  394.         }
  395.     }
  396.     else if(cmpStrtoResNum(command, ksCmdResolveAliasToPath, strResId))
  397.     {
  398.                 // GetResolvedPath
  399.                 // This is the same as ResolveAlias except that
  400.                 // we return a full path rather than a FSSpec.
  401.                 
  402.         if(paramPtr->paramCount<2)
  403.         {
  404.             returnMsgNum(paramPtr, ksErrMissingParam, strResId, err);
  405.             return;
  406.         }
  407.         else
  408.         {
  409.             handleToCstr(aliasStr, paramPtr->params[1]);
  410.             convertHexStrToData(aliasStr, &((Handle) hAlias));
  411.             if(err = ResolveAlias(nil, hAlias, &fileSpec, &bWasChanged))
  412.             {
  413.                 returnMsgNum(paramPtr, ksErrResolveAlias, strResId, err);
  414.                 DisposHandle((Handle) hAlias);
  415.                 return;
  416.             }
  417.             bResolveAliasChains = true;
  418.             if(err = ResolveAliasFile(&fileSpec, bResolveAliasChains,
  419.                                         &bTargetIsFolder, &bWasAliased))
  420.             {
  421.                 returnMsgNum(paramPtr, ksErrResolveAliasFile, strResId, err);
  422.                 DisposHandle((Handle) hAlias);
  423.                 return;
  424.             }
  425.             DisposHandle((Handle) hAlias);
  426.             pathNameFromFSSpec(resultStr, &fileSpec);
  427.             paramPtr->returnValue = copyStrToHand(p2cstr(resultStr));
  428.             return;
  429.         }
  430.     }
  431.     else
  432.     {
  433.         returnMsgNum(paramPtr, ksErrCommandHuh, strResId, kNoErrNum);
  434.         return;
  435.     }
  436. }    /*    --------------------------------------------    entryPoint    */
  437.  
  438. /*
  439.         Functions
  440. */
  441.  
  442. void addColon(volName)
  443. /*
  444.     Add a colon to the end of volName.
  445.     If one is already there, leave it.
  446. */
  447.     Str255    volName;
  448. {
  449.     if(volName[volName[0]]!=kColon)
  450.     {    /*    add colon at end    */
  451.         volName[0]++;
  452.         volName[volName[0]] = kColon;
  453.     }
  454. }    /*    --------------------------------------------    addColon    */
  455.  
  456. void addNumItemToList(pList, num)
  457. /*
  458.     Add num to pList.
  459.     
  460.     Preceed each item with a comma.
  461.     The comma will not be added as
  462.     the first item in a string or
  463.     the first item in a line.
  464. */
  465.     char    *pList;
  466.     long    num;
  467. {
  468.     Str255    tempPstr;
  469.  
  470.     NumToString(num, tempPstr);
  471.     addStrItemToList(pList, p2cstr(tempPstr));
  472. }    /*    --------------------------------------------    addNumItemToList    */
  473.  
  474. void addStrItemToList(pList, pAdd)
  475. /*
  476.     Add pAdd to pList.
  477.     
  478.     Preceed each item with a comma.
  479.     The comma will not be added as
  480.     the first item in a string or
  481.     the first item in a line.
  482. */
  483.     char    *pList,
  484.             *pAdd;
  485. {
  486.     short    len;
  487.     
  488.     if(len=strlen(pList))
  489.         if(pList[len-1]!=kReturn)
  490.             strcat(pList, kCommaStr);
  491.     strcat(pList, pAdd);
  492. }    /*    --------------------------------------------    addStrItemToList    */
  493.  
  494. short cmpStrtoResNum(theString, theStrNum, strResId)
  495. /*
  496.  
  497.     08/17/90 1.0a2 MJP    new (GFXMenu)
  498.     11-16-90 1.0d4 JRP    add strResId as parameter
  499. */
  500.     Str255        theString;
  501.     short        theStrNum,
  502.                 strResId;
  503.     
  504. {
  505.     Str255        ResString;
  506.     
  507.     GetIndString(ResString, strResId, theStrNum);
  508.     return (equalPstr(ResString, theString));
  509. }    /*    --------------------------------------------    cmpStrtoResNum    */
  510.  
  511. void convertDataToHexStr(hexStr, han)
  512. /*
  513.     Convert the handle data to a string
  514.     of ASCII hex characters.
  515. */
  516.     char    *hexStr;
  517.     Handle    han;
  518. {
  519.     Ptr        pData;
  520.     long    i;
  521.     Size    hanSize;
  522.     Byte    dataByte,
  523.             byteValue,
  524.             hiNibble,
  525.             loNibble;
  526.     
  527.     hanSize = GetHandleSize(han);
  528.     HLock(han);
  529.     pData = *han;
  530.     for(i=0; i<hanSize; i++)
  531.     {
  532.         dataByte = *pData++;
  533.         byteValue = (dataByte & 0xF0) >> 4;
  534.         if(byteValue>9)
  535.             hiNibble = 'A' + (byteValue - 10);
  536.         else
  537.             hiNibble = '0' + byteValue;
  538.         byteValue = dataByte & 0x0F;
  539.         if(byteValue>9)
  540.             loNibble = 'A' + (byteValue - 10);
  541.         else
  542.             loNibble = '0' + byteValue;
  543.         *hexStr++ = hiNibble;
  544.         *hexStr++ = loNibble;
  545.     }
  546.     HUnlock(han);
  547.     *hexStr = '\0';        /*    add terminator    */
  548. }    /*    --------------------------------------- convertDataToHexStr    */
  549.  
  550. void convertFSSpecToStr(str, pSpec)
  551. /*
  552.     Convert an FSSpec to a string.
  553. */
  554.     char        *str;
  555.     FSSpecPtr    pSpec;
  556. {
  557.     char        tempStr[256];
  558.     
  559.     *str = 0;
  560.     addNumItemToList(str, pSpec->vRefNum);
  561.     addNumItemToList(str, pSpec->parID);
  562.     copyPtoCstr(tempStr, pSpec->name);
  563.     addStrItemToList(str, tempStr);
  564. }    /*    --------------------------------------- convertFSSpecToStr    */
  565.  
  566. void convertHexStrToData(hexStr, hanReturn)
  567. /*
  568.     Convert the ASCII hex characters
  569.     to a handle of data.
  570.     
  571.     Handle is created in this function.
  572. */
  573.     char    *hexStr;
  574.     Handle    *hanReturn;
  575. {
  576.     Handle    han;
  577.     Ptr        pData;
  578.     short    lenHexStr;
  579.     Size    hanSize;
  580.     Byte    hiAsciiNibble,
  581.             loAsciiNibble,
  582.             dataValue;
  583.     
  584.     lenHexStr = strlen(hexStr);
  585.     if(lenHexStr & 0x01)
  586.     {
  587.         DebugStr("\pconvertHexStrToData: hex string is odd length");
  588.         *hanReturn = nil;
  589.         return;
  590.     }
  591.     hanSize = lenHexStr >> 1;            /*    one-half                */
  592.     han = NewHandleClear(hanSize);
  593.     if(han==nil || MemError())
  594.     {
  595.         DebugStr("\pconvertHexStrToData: NewHandleClear failed");
  596.         *hanReturn = nil;
  597.         return;
  598.     }
  599.     HLock(han);
  600.     pData = *han;
  601.     while(*hexStr)
  602.     {
  603.         hiAsciiNibble = *hexStr++;
  604.         if(hiAsciiNibble>'9')
  605.             dataValue = ((10 + hiAsciiNibble - 'A') << 4);
  606.         else
  607.             dataValue = (hiAsciiNibble - '0') << 4;
  608.         loAsciiNibble = *hexStr++;
  609.         if(loAsciiNibble>'9')
  610.             dataValue |= 10 + loAsciiNibble - 'A';
  611.         else
  612.             dataValue |= loAsciiNibble - '0';
  613.         *pData++ = dataValue;
  614.     }
  615.     HUnlock(han);
  616.     *hanReturn = han;
  617. }    /*    --------------------------------------- convertHexStrToData    */
  618.  
  619. void convertStrToFSSpec(listStr, pSpec)
  620. /*
  621.     Convert  a string to an FSSpec.
  622. */
  623.     char        *listStr;
  624.     FSSpecPtr    pSpec;
  625. {
  626.     char        tempStr[256];
  627.     long        tempLong;
  628.     
  629.     getItemFromCList(listStr, 1, tempStr);
  630.     StringToNum(c2pstr(tempStr), &tempLong);
  631.     pSpec->vRefNum = tempLong;
  632.     getItemFromCList(listStr, 2, tempStr);
  633.     StringToNum(c2pstr(tempStr), &(pSpec->parID));
  634.     getItemFromCList(listStr, 3, pSpec->name);
  635. }    /*    --------------------------------------- convertStrToFSSpec    */
  636.  
  637. void copyPtoCstr(Cstr, Pstr)
  638. /*
  639.     Copy the Pstr to the Cstr.
  640.     Don't do it in-place like ToCstr.
  641. */
  642.     Str255    Pstr;
  643.     char    *Cstr;
  644. {
  645.     short    i;
  646.     
  647.     for(i=1; i<=Pstr[0]; i++)
  648.         *Cstr++ = Pstr[i];
  649.     *Cstr = 0;
  650. }    /*    --------------------------------------- copyPtoCstr            */
  651.  
  652. Handle copyStrToHand(str)
  653. /*
  654.     Create a handle and copy the string to it.
  655.     Return the handle.
  656. */
  657.     char *str;
  658. {
  659.     Handle    newHndl;
  660.  
  661.     newHndl = (Handle) NewHandle((long) strlen(str) + 1);
  662.     HLock(newHndl);
  663.     strcpy(*newHndl, str);
  664.     HUnlock(newHndl);
  665.     return(newHndl);
  666. }    /*    --------------------------------------------    copyStrToHand        */
  667.  
  668. void deleteColon(volName)
  669. /*
  670.     Delete a colon from the end of volName.
  671.     If one isn't there, forget it.
  672. */
  673.     Str255    volName;
  674. {
  675.     if(volName[volName[0]]==kColon)
  676.         volName[0]--;
  677. }    /*    --------------------------------------------    deleteColon            */
  678.  
  679. short equalPstr(s1, s2)
  680. /*
  681.     Compare s1 and s2.
  682.     If their contents are equal and they are of equal length, return TRUE.
  683.     Comparison is not case-sensitive.
  684. */
  685.     Str255    s1,
  686.             s2;
  687. {
  688.     short    i,
  689.             c1,
  690.             c2;
  691.     
  692.     if(s1[0]!=s2[0])
  693.         return false;
  694.     for(i=1; i<=s1[0]; i++)
  695.     {
  696.         c1 = tolower(s1[i]);
  697.         c2 = tolower(s2[i]);
  698.         if(c1!=c2)
  699.             return false;
  700.     }
  701.     return true;
  702. }    /*    --------------------------------------------    equalPstr            */
  703.  
  704. short findStrResId(resName)
  705. /*
  706.     Given the name of a STR# resource, return
  707.     its ID number.  This lets us use names instead
  708.     of ID's for tracking STR# resources.
  709. */
  710.     char    *resName;
  711. {
  712.     Handle    hRes;
  713.     short    theID;
  714.     ResType    theType;
  715.     Str255    theName;
  716.     
  717.     strcpy(theName, resName);
  718.     hRes = GetNamedResource('STR#', c2pstr(theName));
  719.     if(!hRes || ResError())
  720.         return 0;
  721.     GetResInfo(hRes, &theID, &theType, theName);
  722.     if(ResError()==resNotFound)
  723.         return 0;
  724.     else
  725.         return theID;
  726. }    /*    --------------------------------------------    findStrResId        */
  727.  
  728. void getItemFromCList(itemListCstr, itemNum, itemCstr)
  729. /*
  730.     Return the itemNum-th item in the itemListCstr.
  731.     Stops at end of string or Return character (end of HyperCard line).
  732.     Returns terminator if item not present.
  733.     Does not return any punctuation (comma or return).
  734. */
  735.     char    *itemListCstr;
  736.     short    itemNum;
  737.     char    *itemCstr;
  738. {
  739.     short    itemCnt=1;
  740.  
  741.                                     /*    Count commas to get itemNum-th item    */
  742.     while(itemCnt<itemNum && *itemListCstr!=0 && *itemListCstr!=kReturn)
  743.         if(*itemListCstr++==kComma)
  744.             itemCnt++;
  745.                                     /*    Copy itemNum-th item                */
  746.                                     /*    skip leading spaces                    */
  747.     if(itemCnt==itemNum)
  748.     {
  749.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr==kSpace)
  750.             itemListCstr++;
  751.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr!=kComma)
  752.             *itemCstr++ = *itemListCstr++;
  753.     }
  754.     *itemCstr = kCterm;
  755.         
  756. }    /*    --------------------------------------------    getItemFromCList        */
  757.  
  758. void getItemFromPList(itemListPstr, itemNum, itemPstr)
  759. /*
  760.     Return the itemNum-th item in the itemListPstr
  761. */
  762.     Str255    itemListPstr;
  763.     short    itemNum;
  764.     Str255    itemPstr;
  765. {
  766.     short    i=1,
  767.             j=0,
  768.             itemCnt=1;
  769.                                     /*    Count commas to get itemNum-th item    */
  770.     while(itemCnt<itemNum && i<itemListPstr[0])
  771.         if(itemListPstr[i++]==kComma)
  772.             itemCnt++;
  773.                                     /*    Copy itemNum-th item                */
  774.     if(itemCnt==itemNum)
  775.         while(i<=itemListPstr[0] && itemListPstr[i]!=kComma)
  776.             itemPstr[++j] = itemListPstr[i++];
  777.     itemPstr[0] = j;
  778. }    /*    --------------------------------------------    getItemFromPList        */
  779.  
  780. void handleToCstr(str, hndl)
  781. /*
  782.     Return a copy of the string contained in the handle.
  783.     If the handle is NIL, return an empty string.
  784. */
  785.     char    *str;
  786.     Handle    hndl;
  787. {
  788.     if(hndl==nil)
  789.         *str = kCterm;
  790.     else
  791.     {
  792.         HLock(hndl);
  793.         strcpy(str, *hndl);
  794.         HUnlock(hndl);
  795.     }
  796. }    /*    --------------------------------------------    handleToCstr        */
  797.  
  798. void handleToPstr(str, hndl)
  799. /*
  800.     Return a copy of the string contained in the handle.
  801.     If the handle is NIL, return an empty string.
  802. */
  803.     Str255    str;
  804.     Handle    hndl;
  805. {
  806.     if(hndl==nil)
  807.         str[0] = 0;
  808.     else
  809.     {
  810.         HLock(hndl);
  811.         strcpy((char *)str, *hndl);
  812.         HUnlock(hndl);
  813.         c2pstr(str);
  814.     }
  815. }    /*    --------------------------------------------    handleToPstr        */
  816.  
  817. void insertParent(pList, pParentToAdd, pSeparatorChar)
  818. /*
  819.     Insert pParentToAdd and pSeparatorChar before pList.
  820.  
  821.     Note that pSeparatorChar is a C-string (has terminator.)
  822. */
  823.     char    *pList,
  824.             *pParentToAdd,
  825.             *pSeparatorChar;
  826. {
  827.     char    tempList[1024];
  828.     
  829.     strcpy(tempList, pParentToAdd);
  830.     strcat(tempList, pSeparatorChar);    /*    add suffix following parent    */
  831.     strcat(tempList, pList);            /*    put list after new parent    */
  832.     strcpy(pList, tempList);            /*    copy back to list            */
  833. }    /*    --------------------------------------------    insertParent    */
  834.  
  835. void pathNameFromFSSpec(Str255 pathName, FSSpec* fileSpec)
  836. /*
  837.     Make the complete pathname from the FSSpec.
  838.     Builds the full path by working it way up from the
  839.     file name through all directories until it reaches the volume.
  840.  
  841.     pathNameFromFSSpec adapted from pathNameFromDirID by JRP.
  842.     pathNameFromDirID converted from Pascal by JRP.
  843.     Original Pascal courtesy of Skeptic and Cynic.
  844.     
  845.     14-May-91    PBGetCatInfo returns "file not found" error
  846.                 after converting from Think to MPW.
  847.                 Reason was that Think automatically
  848.                 dereferenced CurDirStore to a long dirID.
  849.  
  850.     FSSpec* fileSpec;    pass FSSpec
  851.     Str255    pathName;    return complete path name
  852. */
  853. {
  854.     CInfoPBRec    infoBlock;
  855.     Str255        directoryStr;
  856.     OSErr        err=noErr;
  857.             // Start with file name.
  858.     PLstrcpy(pathName, fileSpec->name);
  859.     directoryStr[0] = 0;
  860.     infoBlock.dirInfo.ioCompletion = nil;
  861.     infoBlock.dirInfo.ioNamePtr = (StringPtr) directoryStr;
  862.     infoBlock.dirInfo.ioDrParID = fileSpec->parID;
  863.             // Walk up the directory tree.
  864.     do
  865.     {
  866.         infoBlock.dirInfo.ioVRefNum = fileSpec->vRefNum;
  867.         infoBlock.dirInfo.ioFDirIndex = -1;
  868.         infoBlock.dirInfo.ioDrDirID = infoBlock.dirInfo.ioDrParID;
  869.         err = PBGetCatInfo(&infoBlock, false);
  870.         PLstrcat(directoryStr, "\p:");
  871.         PLstrcat(directoryStr, pathName);
  872.         PLstrcpy(pathName, directoryStr);
  873.     }
  874.     while(err==noErr && infoBlock.dirInfo.ioDrDirID!=2);
  875. }                                /*    end pathNameFromDirID    ----------------    */
  876.  
  877. void returnMsgNum(paramPtr, strNum, strResId, num)
  878. /*
  879.     Given the STR# number and a number,
  880.     place the string and the number
  881.     in the return to HyperCard.
  882.     The num is optional, if 0 then it is not placed.
  883.     
  884.     11-16-90 1.0d4 JRP    add strResId as a parameter
  885. */
  886.     XCmdPtr     paramPtr;        /*    the HyperCard connection        */
  887.     short        strNum,
  888.                 strResId;
  889.     long        num;
  890. {
  891.     Str255        resPstr;
  892.     char        resultStr[256];
  893.     
  894.     GetIndString(resPstr, strResId, strNum);
  895.     strcpy(resultStr, p2cstr(resPstr));
  896.     if(num!=kNoErrNum)
  897.         addNumItemToList(resultStr, num);
  898.     paramPtr->returnValue = copyStrToHand(resultStr);
  899. }    /*    --------------------------------------------    returnMsgNum    */
  900.     
  901.